/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#ifndef INCLUDE_SHADER_CURVE
#define INCLUDE_SHADER_CURVE

#include "shader_binding_ID.h"
#include "shader_built_in_functions.h"
//#include "shader_tranform.h"


#define DEF_CURVE_SUBDIV 32


struct S_CurvePick {
	vec2 pick_coord;
	vec2 pick_dis;
};


#define DEF_CONTORL_POINT_AUTO 0
#define DEF_CONTORL_POINT_FREE 1
#define DEF_CONTORL_POINT_ALGNED 2
#define DEF_CONTORL_POINT_VECTOR 3


struct S_CurvePoint2 {
	vec2	L_point;
	vec2	R_point;
	vec2	value;
	uvec2	ID_Color;

	uvec2	Select_Type;
};

struct S_CurvePoint {
	vec2	value;
	vec2	control;

	uvec2	ID_Color;
	uvec2	Select_Type;
};


struct S_CurvePoint3D {
	vec3	value;
	vec3	L_point;
	vec3	R_point;
	uvec3	ID_Type_Color;
};

struct S_Waveform {
	vec2		m_SampleOffset;
	//uint64_t	m_Offset_point;
	float		m_SampleWidth;
	float		m_SampleHigth;
	
	float		m_SampleNum;
	uint		m_PassNum;
	uint		m_Color;
};



#ifdef __cplusplus

//#include <向量.h>
#include <basic_vec.h>

// GLSL Type
using uint = unsigned int;
#define in
#define out
#define inout






#define DEF_glsl_Cal_CutCircleRadius Inline float f_glsl_Cal_CutCircleRadius(const S_CurvePoint2& cp)
//#define DEF_glsl_CurveSample Inline float f_glsl_CurveSample(float32 sample, const S_CurvePoint& curve, const vec2 cl)

#define DEF_glsl_Cal_CatmullRom2 Inline vec2 f_glsl_cal_CatmullRom2(const vec2& p0, const vec2& p1, const vec2& p2, const vec2& p3, float32 t)
#define DEF_glsl_Cal_CatmullRom3 Inline vec3 f_glsl_cal_CatmullRom3(const vec3& p0, const vec3& p1, const vec3& p2, const vec3& p3, float32 t)

#define DEF_glsl_Cal_Hermite2 Inline vec2 f_glsl_cal_Hermite2(const vec2& p0, const vec2& p1, const vec2& p2, const vec2& p3, float32 t)
#define DEF_glsl_Cal_Hermite3 Inline vec3 f_glsl_cal_Hermite3(const vec3& p0, const vec3& p1, const vec3& p2, const vec3& p3, float32 t)

#define DEF_glsl_Cal_CubicInterpolate2 Inline vec2 f_glsl_cal_CubicInterpolate2(const vec2& p0, const vec2& p1, const vec2& p2, const vec2& p3, float32 t)
#define DEF_glsl_Cal_CubicInterpolate3 Inline vec3 f_glsl_cal_CubicInterpolate3(const vec3& p0, const vec3& p1, const vec3& p2, const vec3& p3, float32 t)

#else

#define Inline

#define DEF_glsl_Cal_CutCircleRadius Inline float f_glsl_Cal_CutCircleRadius(in S_CurvePoint2 cp)

#define DEF_glsl_Cal_CatmullRom2 vec2 f_glsl_cal_CatmullRom2(in vec2 p0, in vec2 p1, in vec2 p2, in vec2 p3, float t)
#define DEF_glsl_Cal_CatmullRom3 vec3 f_glsl_cal_CatmullRom3(in vec3 p0, in vec3 p1, in vec3 p2, in vec3 p3, float t)

#define DEF_glsl_Cal_Hermite2 vec2 f_glsl_cal_Hermite2(in vec2 p0, in vec2 p1, in vec2 p2, in vec2 p3, float t)
#define DEF_glsl_Cal_Hermite3 vec3 f_glsl_cal_Hermite3(in vec3 p0, in vec3 p1, in vec3 p2, in vec3 p3, float t)

#define DEF_glsl_Cal_CubicInterpolate2 vec2 f_glsl_cal_CubicInterpolate2(in vec2 p0, in vec2 p1, in vec2 p2, in vec2 p3, float t)
#define DEF_glsl_Cal_CubicInterpolate3 vec3 f_glsl_cal_CubicInterpolate3(in vec3 p0, in vec3 p1, in vec3 p2, in vec3 p3, float t)


//void f_curve_point_control(
//	in uint Instance,
//	//S_CurvePoint m_Curve[],
//	out vec2 s_point,
//	out vec2 e_point,
//	out vec2 L_dir,
//	out vec2 R_dir,
//	out vec2 V_dir,
//	out float l_len,
//	out float r_len,
//	out float v_len,
//	out S_CurvePoint s_curve,
//	out S_CurvePoint e_curve,
//	out vec4 color[2],
//	in int num
//) {
//
//	uint s_ID = Instance;
//	uint e_ID = Instance + 1;
//
//	s_curve = m_Curve[s_ID];
//	e_curve = m_Curve[e_ID];
//
//	color[0] = f_glsl_buildColor(s_curve.ID_Color.y);
//	color[1] = f_glsl_buildColor(e_curve.ID_Color.y);
//
//	s_point = s_curve.value;
//	e_point = e_curve.value;
//
//	L_dir = s_curve.R_point - s_point;
//	R_dir = e_curve.L_point - e_point;
//	V_dir = e_curve.L_point - s_curve.R_point;
//
//	l_len = length(L_dir) / num;
//	r_len = length(R_dir) / num;
//	v_len = length(V_dir) / (num * 2);
//
//	L_dir = normalize(L_dir);
//	R_dir = normalize(R_dir);
//	V_dir = normalize(V_dir);
//
//}


//void f_curve_line
vec4 f_curve_point_bind_Left(
	in vec2 s_point,
	in vec2 L_dir,
	in vec2 V_dir,
	in float l_len,
	in float v_len,
	in S_CurvePoint2 s_curve,
	in float L,
	in uint i
) {
	vec2 s = L_dir * (l_len * i) + s_point;
	vec2 e = V_dir * (v_len * i) + s_curve.R_point;

	e = e - s;
	vec4 vert = vec4(s + e * L, 0, 1);

	return vert;
}


vec4 f_curve_point_bind_Right(
	in vec2 R_dir,
	in vec2 V_dir,
	in float r_len,
	in float v_len,
	in S_CurvePoint2 s_curve,
	in S_CurvePoint2 e_curve,
	in float L,
	in uint i
) {

	vec2 s = s_curve.R_point + V_dir * (v_len * (i + 16));
	vec2 e = e_curve.L_point - R_dir * (r_len * i);

	e = e - s;
	vec4 vert = vec4(s + e * L, 0, 1);

	return vert;
}







#endif


struct S_SampleCurve {
	uint m_buferOffset;
	uint m_num;
};



Inline void f_curve_sampling(){

}

Inline vec2 f_curve_cal_point(S_CurvePoint2 s_curve, S_CurvePoint2 e_curve, float gap){
	vec2 v1 = s_curve.value + (s_curve.R_point - s_curve.value) * gap;
	vec2 v2 = s_curve.R_point + (e_curve.L_point - s_curve.R_point) * gap;
	vec2 v3 = e_curve.L_point + (e_curve.value - e_curve.L_point) * gap;
	
	vec2 p1 = (v2 - v1) * gap + v1;
	vec2 p2 = (v3 - v2) * gap + v2;

	return p1 + (p2 - p1) * gap;
}

Inline vec2 f_cubicCurve_sample(vec2 s, vec2 sc, vec2 ec, vec2 e, float gap){
	vec2 v1 = s + (sc - s) * gap;
	vec2 v2 = sc + (ec - sc) * gap;
	vec2 v3 = ec + (e - ec) * gap;

	vec2 p1 = (v2 - v1) * gap + v1;
	vec2 p2 = (v3 - v2) * gap + v2;

	return p1 + (p2 - p1) * gap;
}

Inline vec2 f_quadraticCurve_sample(vec2 s, vec2 c, vec2 e, float gap){
	vec2 v1 = s + (c - s) * gap;
	vec2 v2 = c + (e - c) * gap;

	vec2 p1 = (v2 - v1) * gap + v1;

	return p1;
}


Inline float f_curve_cal_toLineCenterDis(
	in S_CurvePoint2 s_curve, 
	in S_CurvePoint2 e_curve, 
	in vec2 coord, 
	in float step_gap, 
	in float areaSize) 
	{
	vec2 vert0 = f_curve_cal_point(s_curve, e_curve, step_gap*0.03125);
	vec2 vert1 = f_curve_cal_point(s_curve, e_curve, (step_gap+1)*0.03125);
	
	vec2 centerPoint = (vert1 - vert0);
	float radius = length(centerPoint) * 0.5 + areaSize;

	centerPoint = vert0 + centerPoint * 0.5;

	return length(coord - centerPoint) - radius;
}

Inline S_CurvePoint2 f_curve_cal_pre(in S_CurvePoint2 s_curve, in S_CurvePoint2 e_curve){
	S_CurvePoint2 point = s_curve;
	point.value = s_curve.L_point;
	//point.L_point = point.value - vec_normalize(e_curve.L_point - point.value)*2;
	//point.R_point = point.value+0.001;
	//point.value = s_curve.L_point;
	//point.L_point = point.value;
	//point.R_point = point.value;
	return point;
}

Inline S_CurvePoint2 f_curve_cal_next(S_CurvePoint2 e_curve){
	S_CurvePoint2 point = e_curve;
	point.value = e_curve.R_point;
	return point;
}



DEF_glsl_Cal_CutCircleRadius{
	vec2 size = cp.R_point - cp.L_point;
	return min(cp.value.x, min(abs(size.x * 0.5), abs(size.y * 0.5)));
}


DEF_glsl_Cal_CatmullRom2 {
	const float t2 = t * t;
	const float t3 = t2 * t;

	// 储存中间值以减少重复计算
	const vec2 two_p1 = p1 * 2.0f;
	const vec2 p0_p2 = p0 - p2;
	const vec2 p0_min_5p1_plus_4p2_minus_p3 = (p0 * 2.0f - p1 * 5.0f + p2 * 4.0f- p3);
	const vec2 p0_min_3p1_plus_3p2_minus_p3 = (-p0 + p1 * 3.0f - p2 * 3.0f + p3);

	vec2 point;
	point = (two_p1 + p0_p2 * t + p0_min_5p1_plus_4p2_minus_p3 * t2 + p0_min_3p1_plus_3p2_minus_p3 * t3) * 0.5f;

	point.x = 0.5f * ((2.0f * p1.x) + (-p0.x + p2.x) * t +
		(2.0f * p0.x - 5.0f * p1.x + 4.0f * p2.x - p3.x) * t2 +
		(-p0.x + 3.0f * p1.x - 3.0f * p2.x + p3.x) * t3);
	point.y = 0.5f * ((2.0f * p1.y) + (-p0.y + p2.y) * t +
		(2.0f * p0.y - 5.0f * p1.y + 4.0f * p2.y - p3.y) * t2 +
		(-p0.y + 3.0f * p1.y - 3.0f * p2.y + p3.y) * t3);

	return point;
}

DEF_glsl_Cal_CatmullRom3 {
	float t2 = t * t;
	float t3 = t2 * t;

	vec3 a = (p3 - p0 - (p2 - p1) * 3.0f) * 0.5f;
	vec3 b = (p0 + p2 * 2.0f- p1 * 2.0f- p3) * 0.5f;
	vec3 c = p2 - p0 * 0.5f;

	return a * t3 + b * t2 + c * t + p1;
}



DEF_glsl_Cal_CubicInterpolate2 {
	vec2 v;

	float a0, a1, a2, a3, mu2;
	

	mu2 = t * t;
	a0 = p3.x - p2.x - p0.x + p1.x;
	a1 = p0.x - p1.x - a0;
	a2 = p2.x - p0.x;
	a3 = p1.x;
	v.x = a0 * t * mu2 + a1 * mu2 + a2 * t + a3;


	a0 = p3.y - p2.y - p0.y + p1.y;
	a1 = p0.y - p1.y - a0;
	a2 = p2.y - p0.y;
	a3 = p1.y;
	v.y = a0 * t * mu2 + a1 * mu2 + a2 * t + a3;

	return v;
}



DEF_glsl_Cal_Hermite2 {
	const float t2 = t * t;
	const float t3 = t2 * t;

	// 储存中间值以减少重复计算
	const vec2 two_p1 = p1 * 2.0f;
	const vec2 p0_p2 = p0 - p2;
	const vec2 p0_min_5p1_plus_4p2_minus_p3 = (p0 * 2.0f - p1 * 5.0f + p2 * 4.0f - p3);
	const vec2 p0_min_3p1_plus_3p2_minus_p3 = (-p0 + p1 * 3.0f - p2 * 3.0f + p3);

	vec2 point;
	point = (two_p1 + p0_p2 * t + p0_min_5p1_plus_4p2_minus_p3 * t2 + p0_min_3p1_plus_3p2_minus_p3 * t3) * 0.5f;

	point.x = 0.5f * ((2.0f * p1.x) + (-p0.x + p2.x) * t +
		(2.0f * p0.x - 5.0f * p1.x + 4.0f * p2.x - p3.x) * t2 +
		(-p0.x + 3.0f * p1.x - 3.0f * p2.x + p3.x) * t3);
	point.y = 0.5f * ((2.0f * p1.y) + (-p0.y + p2.y) * t +
		(2.0f * p0.y - 5.0f * p1.y + 4.0f * p2.y - p3.y) * t2 +
		(-p0.y + 3.0f * p1.y - 3.0f * p2.y + p3.y) * t3);

	return point;
}


//DEF_glsl_Cal_Hermite3 {
//	float h00 = 2 * t * t * t - 3 * t * t + 1;  
//	float h10 = -2 * t * t * t + 3 * t * t;    
//	float h01 = t * t * t - 2 * t * t + t;   
//	float h11 = t * t * t - t * t;       
//
//	// Compute the interpolated position along the curve.
//	vec3 interpolated_point;
//	interpolated_point.x = h00 * p0.x + h10 * p1.x + h01 * t0.x + h11 * t1.x;
//	interpolated_point.y = h00 * p0.y + h10 * p1.y + h01 * t0.y + h11 * t1.y;
//	interpolated_point.z = h00 * p0.z + h10 * p1.z + h01 * t0.z + h11 * t1.z;
//
//	return interpolated_point;
//}


Inline vec3 f_glsl_cal_CubicCurve(in vec3 pointA, in vec3 R_point, in vec3 pointB, in vec3 L_point, float t) {
	vec3 v1 = R_point - pointA;
	vec3 v2 = pointB - L_point;

	vec3 p1 = v1 * t + pointA;
	vec3 p2 = v2 * t + L_point;

	vec3 t0 = (p2 - p1) * t + R_point;

	vec3 t1 = (t0 - p1) * t + p1;
	vec3 t2 = (p2 - t0) * t + t0;

	return (t2 - t1) * t + t1;
}


#undef in
#undef out

#endif //TRANSFORM












